package cc.autoapi.pucong.auto.flow.core.flow.execNode.exec;

import cc.autoapi.pucong.auto.flow.core.flow.execNode.entity.api.ApiHandlerMsgDto;
import cc.autoapi.pucong.auto.flow.core.flow.execNode.entity.node.NodeHandlerMsgDto;
import cc.autoapi.pucong.auto.flow.core.flow.execNode.entity.node.TaskNode;
import cc.autoapi.pucong.auto.flow.core.flow.execNode.entity.task.ApiExecResult;
import cc.autoapi.pucong.auto.flow.core.flow.execNode.exception.AutoDesignException;
import cc.autoapi.pucong.auto.flow.core.flow.execNode.exec.publish.ProcessExecApiPublish;
import cc.autoapi.pucong.auto.flow.core.flow.execNode.exec.publish.ProcessExecNodePublish;
import cc.autoapi.pucong.auto.flow.core.flow.execNode.selfenum.NodeTypeEnum;
import cc.autoapi.pucong.auto.flow.core.flow.execNode.selfenum.RunStatusEnum;
import cc.autoapi.pucong.auto.flow.core.flow.execNode.utils.FlowThreadPoolUtils;
import cn.hutool.core.lang.Assert;

import java.util.*;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

public class ProcessExecStart implements ProcessExecInterface {

    private String apiId;
    private String instanceId;

    public ProcessExecStart(String apiId,
                            String instanceId,
                            Map<String, Object> queryParamMap,
                            Map<String, String> headerParamMap,
                            Map<String, Object> bodyParamMap) {
        if (queryParamMap == null) {
            queryParamMap = new HashMap<>(16);
        }
        if (headerParamMap == null) {
            headerParamMap = new HashMap<>(16);
        }
        if (bodyParamMap == null) {
            bodyParamMap = new HashMap<>(16);
        }
        this.apiId = apiId;
        this.instanceId = instanceId;
        checkParams();
        // 设置缓存
        DataBus.setQueryParamMap(instanceId, queryParamMap);
        DataBus.setHeaderParamMap(instanceId, headerParamMap);
        DataBus.setBodyParamMap(instanceId, bodyParamMap);
    }

    private void checkParams() {
        Assert.notBlank(apiId);
        Assert.notBlank(instanceId);
        List<TaskNode> taskNodeList = DataBus.getTaskNodeList(apiId);
        if (taskNodeList == null || taskNodeList.size() == 0) {
            throw new AutoDesignException("该服务未发布,apiId: " + apiId);
        }
    }


    @Override
    public ApiExecResult start() throws Exception {
        Future<ApiExecResult> objectFuture = startFuture();
        ApiExecResult o = objectFuture.get(30, TimeUnit.SECONDS);
        return o;
    }

    @Override
    public Future<ApiExecResult> startFuture() {
        ProcessExecApiPublish apiPublish = DataBus.getApiPublish();
        apiPublish.publicMessageByAsync(ApiHandlerMsgDto.start(apiId, instanceId));
        // 设置执行状态
        ApiExecResult nodeExecResult = new ApiExecResult();
        nodeExecResult.setRunStatus(RunStatusEnum.执行中);
        DataBus.setApiStatus(instanceId, nodeExecResult);
        // 获取任务节点
        List<TaskNode> taskNodeList = DataBus.getTaskNodeList(apiId);
        // 查询根节点
        TaskNode rootNode = null;
        for (TaskNode execNode : taskNodeList) {
            String nodeType = execNode.getNodeType();
            if (NodeTypeEnum.API_CONFIG.getKey().equals(nodeType)) {
                rootNode = execNode;
            }
            if (NodeTypeEnum.CRON_CONFIG.getKey().equals(nodeType)) {
                rootNode = execNode;
            }
        }
        // 执行节点
        ProcessExecNodePublish nodeExecPublish = DataBus.getNodeExecPublish();
        nodeExecPublish.publicMessageByAsync(new NodeHandlerMsgDto(apiId, instanceId, rootNode.getUuid()));

        Future<ApiExecResult> submit = FlowThreadPoolUtils.getThreadPoolExecutor().submit(() -> {
            // 等待所有节点执行完成
            ApiExecResult apiExecResult = null;
            Boolean status = false;
            while (!status) {
                Thread.sleep(100);
                apiExecResult = DataBus.getApiStatus(instanceId);
                if (apiExecResult != null) {
                    status = apiExecResult.getRunStatus() == RunStatusEnum.执行成功 || apiExecResult.getRunStatus() == RunStatusEnum.执行失败;
                }
            }
            // 清理缓存,延迟5秒执行
            Timer timer = new Timer();
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    clearCatch();
                }
            }, 5000);
            return apiExecResult;
        });
        return submit;
    }

    private void clearCatch() {
        // 清除缓存
        DataBus.removeQueryParamMap(instanceId);
        DataBus.removeHeaderParamMap(instanceId);
        DataBus.removeBodyParamMap(instanceId);
        DataBus.removeExecNodeList(instanceId);
    }
}
